【Clojureでゼロから作るDeep Learning】 1章 Python入門
1.1 Pythonとは
1.2 Pythonのインストール
1.2.1 Pythonのバージョン
2020年3月時点の最新版を利用する。
Clojure 1.10.1
Python 3.8
1.2.2 使用する外部ライブラリ
【Clojure】
Leiningenでプロジェクトを構築する(GitHubリポジトリ: lagenorhynque/deep-learning-from-scratch)。
core.matrix
vectorz-clj
Clatrix
Incanter
code:bash
$ lein new deep-learning-from-scratch
code:clojure
(defproject deep-learning-from-scratch "0.1.0-SNAPSHOT"
:description "FIXME: write description"
:url "http://example.com/FIXME"
:license {:name "EPL-2.0 OR GPL-2.0-or-later WITH Classpath-exception-2.0"
:url "https://www.eclipse.org/legal/epl-2.0/"}
:dependencies [clatrix "0.5.0"
incanter "1.9.3"
net.mikera/core.matrix "0.62.0"
org.clojure/clojure "1.10.1"]
:profiles
{:dev {:source-paths "dev/src"
:dependencies [orchestra "2019.02.06-1"
org.clojure/tools.namespace "1.0.0"]}})
code:dev/src/user.clj
(ns user
(:require clojure.repl :refer :all
clojure.spec.alpha :as s
clojure.tools.namespace.repl
orchestra.spec.test :as stest))
(defn refresh options
(let result (apply clojure.tools.namespace.repl/refresh options)
(stest/instrument)
result))
【Python】
本体をpyenvで、ライブラリと仮想環境をPipenvで管理する。
NumPy
Matplotlib
IPython
code:bash
$ cd deep-learing-from-scratch/
$ pipenv install numpy matplotlib
$ pipenv install -d ipython
code:Pipfile
source
name = "pypi"
url = "https://pypi.org/simple"
verify_ssl = true
dev-packages
ipython = "*"
packages
numpy = "*"
matplotlib = "*"
requires
python_version = "3.8"
1.2.3 Anacondaディストリビューション
1.3 Pythonインタプリタ
【Python】
code:bash
$ pipenv shell
$ python --version
Python 3.8.2
$ ipython
Python 3.8.2 (default, Mar 28 2020, 23:36:11)
Type 'copyright', 'credits' or 'license' for more information
IPython 7.13.0 -- An enhanced Interactive Python. Type '?' for help.
In 1:
code:python
In 1: 1 + 2
Out1: 3
【Clojure】
code:bash
$ lein repl
OpenJDK 64-Bit Server VM warning: Options -Xverify:none and -noverify were deprecated in JDK 13 and will likely be removed in a future release.
nREPL server started on port 64301 on host 127.0.0.1 - nrepl://127.0.0.1:64301
REPL-y 0.4.4, nREPL 0.6.0
Clojure 1.10.1
OpenJDK 64-Bit Server VM 14+36-1461
Docs: (doc function-name-here)
(find-doc "part-of-name-here")
Source: (source function-name-here)
Javadoc: (javadoc java-object-or-class-here)
Exit: Control+D or (exit) or (quit)
Results: Stored in vars *1, *2, *3, an exception in *e
user=>
code:clojure
user=> (+ 1 2)
3
1.3.1 算術計算
Clojureで整数同士の除算 / は割り切れない場合に有理数 clojure.lang.Ratio になる。
code:clojure
user> (- 1 2)
-1
user> (* 4 5)
20
user> (/ 7 5)
7/5
user> (/ 7.0 5)
1.4
user> (/ 7 5.0)
1.4
user> (double (/ 7 5))
1.4
user> (Math/pow 3 2)
9.0
1.3.2 データ型
code:clojure
user> (type 10)
java.lang.Long
user> (type 2.718)
java.lang.Double
user> (type "hello")
java.lang.String
1.3.3 変数
原則として特殊形式 let によるローカル束縛を利用する。
再代入が必要な場合には atom(もしくは volatile!)の利用も検討する。
トップレベルの定義には def マクロ。
code:clojure
user> (let x 10
(println x))
10
nil
user> (let x 100
(println x))
100
nil
user> (let [x 100
y 3.14]
(* x y))
314.0
user> (let [x 100
y 3.14]
(type (* x y)))
java.lang.Double
1.3.4 リスト
Clojureではベクター(vector; clojure.lang.IPersistentVector)またはシーケンス(sequence; clojure.lang.ISeq)など。
破壊的な操作が必要な場合にはJava配列(array)の利用も検討する。
code:clojure
user> (let [a 1 2 3 4 5]
(println a))
1 2 3 4 5
nil
user> (let [a 1 2 3 4 5]
(count a))
5
user> (let [a 1 2 3 4 5]
(nth a 0))
1
user> (let [a 1 2 3 4 5]
(nth a 4))
5
user> (let [a 1 2 3 4 5
a' (assoc a 4 99)]
(println a'))
1 2 3 4 99
nil
user> (let [a 1 2 3 4 5
a' (assoc a 4 99)]
(subvec a' 0 2))
1 2
user> (let [a 1 2 3 4 5
a' (assoc a 4 99)]
(subvec a' 1))
2 3 4 99
user> (let [a 1 2 3 4 5
a' (assoc a 4 99)]
(vec (take 3 a')))
1 2 3
user> (let [a 1 2 3 4 5
a' (assoc a 4 99)]
(vec (drop-last 1 a')))
1 2 3 4
user> (let [a 1 2 3 4 5
a' (assoc a 4 99)]
(vec (drop-last 2 a')))
1 2 3
1.3.5 ディクショナリ
Clojureではマップ(map; clojure.lang.IPersistentMap)。
キーには通常、キーワード(keyword)を利用する。
code:clojure
user> (let me {:height 100}
(:height me))
100
user> (let [me {:height 100}
me' (assoc me :weight 70)]
(println me'))
{:height 100, :weight 70}
nil
1.3.6 ブーリアン
code:clojure
user> (let [hungry? true
sleepy? false]
(type hungry?))
java.lang.Boolean
user> (let [hungry? true
sleepy? false]
(not hungry?))
false
user> (let [hungry? true
sleepy? false]
(and hungry? sleepy?))
false
user> (let [hungry? true
sleepy? false]
(or hungry? sleepy?))
true
1.3.7 if文
Clojureでは if 特殊形式、when マクロ、 cond マクロなど。
code:clojure
user> (let hungry? true
(when hungry?
(println "I'm hungry")))
I'm hungry
nil
user> (let hungry? false
(if hungry?
(println "I'm hungry")
(do (println "I'm not hungry")
(println "I'm sleepy"))))
I'm not hungry
I'm sleepy
nil
1.3.8 for文
Clojureでは doseq マクロなど。
code:clojure
user> (doseq [i 1 2 3]
(println i))
1
2
3
nil
1.3.9 関数
Clojureでは defn マクロなど。
文字列連結は str 関数。
code:clojure
user> (defn hello []
(println "Hello World!"))
#'user/hello
user> (hello)
Hello World!
nil
user> (defn hello object
(println (str "Hello " object "!")))
#'user/hello
user> (hello "cat")
Hello cat!
nil
1.4 Pythonスクリプトファイル
1.4.1 ファイルに保存
code:src/deep_learning_from_scratch/ch01/hungry.clj
(ns deep-learning-from-scratch.ch01.hungry)
(defn -main []
(println "I'm hungry!"))
code:bash
$ lein run -m deep-learning-from-scratch.ch01.hungry
I'm hungry!
lein run でのスクリプト実行はLeiningenの起動まで時間が掛かるため、REPLから実行したほうが素早く試せる。
code:clojure
user> (refresh)
:reloading (deep-learning-from-scratch.core deep-learning-from-scratch.core-test user deep-learning-from-scratch.ch01.hungry)
:ok
user> (deep-learning-from-scratch.ch01.hungry/-main)
I'm hungry!
nil
1.4.2 クラス
Clojureはオブジェクト指向言語ではないためクラスを定義することは稀だが、同等の処理は異なる方法で実現できる。
code:src/deep_learning_from_scratch/ch01/man.clj
(ns deep-learning-from-scratch.ch01.man
(:require clojure.spec.alpha :as s))
(s/def ::name string?)
(s/def ::man (s/keys :req ::name))
(s/fdef hello
:args (s/cat :man ::man))
(defn hello man
(println (str "Hello " (::name man) "!")))
(s/fdef goodbye
:args (s/cat :man ::man))
(defn goodbye man
(println (str "Good-bye " (::name man) "!")))
code:clojure
user> (refresh)
:reloading (deep-learning-from-scratch.ch01.man)
:ok
user> (require 'deep-learning-from-scratch.ch01.man :as man)
nil
user> #::man{:name "David"}
#:deep-learning-from-scratch.ch01.man{:name "David"}
user> (let m #::man{:name "David"}
(man/hello m))
Hello David!
nil
user> (let m #::man{:name "David"}
(man/goodbye m))
Good-bye David!
nil
1.5 NumPy
Clojureでの配列/行列の計算にはcore.matrixを利用する。
1.5.1 NumPyのインポート
core.matrixでは複数の実装を切り替えることができる(cf. Matrix implementations · mikera/core.matrix Wiki)が、ここでは :clatrix という指定でClatrixをデフォルト実装として設定している(vectorz-cljの場合は :vectorz)。
+, -, *, / などの記号演算子は clojure.core.matrix.operators に含まれているので適宜利用する。
code:clojure
user> (require 'clojure.core.matrix :as m)
nil
user> (m/set-current-implementation :clatrix)
:clatrix
1.5.2 NumPy配列の生成
code:clojure
user> (m/array 1.0 2.0 3.0)
(1.0 2.0 3.0)
user> (let [x (m/array 1.0 2.0 3.0)]
(println x))
(1.0 2.0 3.0)
nil
user> (let [x (m/array 1.0 2.0 3.0)]
(type x))
clatrix.core.Vector
1.5.3 NumPyの算術計算
code:clojure
user> (let [x (m/array 1.0 2.0 3.0)
y (m/array 2.0 4.0 6.0)]
(m/add x y))
(3.0 6.0 9.0)
user> (let [x (m/array 1.0 2.0 3.0)
y (m/array 2.0 4.0 6.0)]
(m/sub x y))
(-1.0 -2.0 -3.0)
user> (let [x (m/array 1.0 2.0 3.0)
y (m/array 2.0 4.0 6.0)]
(m/mul x y))
(2.0 8.0 18.0)
user> (let [x (m/array 1.0 2.0 3.0)
y (m/array 2.0 4.0 6.0)]
(m/div x y))
(0.5 0.5 0.5)
user> (let [x (m/array 1.0 2.0 3.0)]
(m/div x 2))
(0.5 1.0 1.5)
1.5.4 NumPyのN次元配列
code:clojure
user> (m/array 1 2] [3 4)
A 2x2 matrix
-------------
1.00e+00 2.00e+00
3.00e+00 4.00e+00
user> (let [A (m/array 1 2] [3 4)]
(println A))
A 2x2 matrix
-------------
1.00e+00 2.00e+00
3.00e+00 4.00e+00
nil
user> (let [A (m/array 1 2] [3 4)]
(m/shape A))
2 2
user> (let [A (m/array 1 2] [3 4)]
(m/element-type A))
double
user> (let [A (m/array 1 2] [3 4)
B (m/array 3 0] [0 6)]
(m/add A B))
A 2x2 matrix
-------------
4.00e+00 2.00e+00
3.00e+00 1.00e+01
user> (let [A (m/array 1 2] [3 4)
B (m/array 3 0] [0 6)]
(m/mul A B))
A 2x2 matrix
-------------
3.00e+00 0.00e+00
0.00e+00 2.40e+01
user> (let [A (m/array 1 2] [3 4)]
(m/mul A 10))
A 2x2 matrix
-------------
1.00e+01 2.00e+01
3.00e+01 4.00e+01
1.5.5 ブロードキャスト
code:clojure
user> (let [A (m/array 1 2] [3 4)
B (m/array 10 20)]
(m/mul A B))
A 2x2 matrix
-------------
1.00e+01 4.00e+01
3.00e+01 8.00e+01
1.5.6 要素へのアクセス
code:clojure
user> (let [X (m/array 51 55] 14 19 [0 4)]
(println X))
A 3x2 matrix
-------------
5.10e+01 5.50e+01
1.40e+01 1.90e+01
0.00e+00 4.00e+00
nil
user> (let [X (m/array 51 55] 14 19 [0 4)]
(m/slice X 0))
(51.0 55.0)
user> (let [X (m/array 51 55] 14 19 [0 4)]
(m/mget X 0 1))
55.0
user> (let [X (m/array 51 55] 14 19 [0 4)]
(doseq row X
(println row)))
A 1x2 matrix
-------------
5.10e+01 5.50e+01
A 1x2 matrix
-------------
1.40e+01 1.90e+01
A 1x2 matrix
-------------
0.00e+00 4.00e+00
nil
user> (let [X (m/array 51 55] 14 19 [0 4)
X' (->> X m/eseq m/array)]
(println X'))
(51.0 55.0 14.0 19.0 0.0 4.0)
nil
user> (let [X (m/array 51 55] 14 19 [0 4)
X' (->> X m/eseq m/array)]
(m/select-indices X' 0 2 4))
(51.0 14.0 0.0)
user> (let [X (m/array 51 55] 14 19 [0 4)
X' (->> X m/eseq m/array)]
(->> X' (filter #(> % 15)) m/array))
(51.0 55.0 19.0)
1.6 Matplotlib
Clojureでのグラフの描画、データの可視化にはIncanterを利用する。
1.6.1 単純なグラフの描画
code:clojure:src/deep_learning_from_scratch/ch01/sin_graph.clj
(ns deep-learning-from-scratch.ch01.sin-graph
(:require clojure.core.matrix :as m
incanter.charts :as charts
incanter.core :as incanter))
(defn -main []
(m/set-current-implementation :clatrix)
(let [x (m/array (range 0 6 0.1))
y (m/sin x)]
(doto (charts/xy-plot x y)
incanter/view)))
code:clojure
user> (refresh)
:reloading (deep-learning-from-scratch.ch01.sin-graph)
:ok
user> (deep-learning-from-scratch.ch01.sin-graph/-main)
#objectorg.jfree.chart.JFreeChart 0x5d338ab9 "org.jfree.chart.JFreeChart@5d338ab9"
https://gyazo.com/8314612d928cb27db4ed3e77a206702a
1.6.2 pyplotの機能
code:clojure:src/deep_learning_from_scratch/ch01/sin_cos_graph.clj
(ns deep-learning-from-scratch.ch01.sin-cos-graph
(:require clojure.core.matrix :as m
incanter.charts :as charts
incanter.core :as incanter))
(defn -main []
(m/set-current-implementation :clatrix)
(let [x (m/array (range 0 6 0.1))
y1 (m/sin x)
y2 (m/cos x)]
(doto (charts/xy-plot x y1
:series-label "sin"
:x-label "x"
:y-label "y"
:title "sin & cos"
:legend true)
(charts/add-lines x y2
:series-label "cos")
(charts/set-stroke :dataset 1
:dash 5)
incanter/view)))
code:clojure
user> (refresh)
:reloading (deep-learning-from-scratch.ch01.sin-cos-graph)
:ok
user> (deep-learning-from-scratch.ch01.sin-cos-graph/-main)
#objectorg.jfree.chart.JFreeChart 0x67607a5a "org.jfree.chart.JFreeChart@67607a5a"
https://gyazo.com/91faeed00c163073b6c99cb6c54a3af5
1.6.3 画像の表示
1.7 まとめ
#Clojureで『ゼロから作るDeep_Learning』学習メモ #Clojure #Python